package cn.com.hhrcw.enterprise.web;

import cn.com.hhrcw.enterprise.params.MobileEnParams;
import cn.com.hhrcw.entity.SysUser;
import cn.com.hhrcw.service.ISysUserService;
import cn.com.hhrcw.sms.service.ISysSmsTemplateService;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.util.IPUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.ui.ModelMap;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 验证码
 *
 * @author lixingxing
 * @since 2020年08月12日16:54:16
 */
@RestController
@RequestMapping("/code")
@Slf4j
@Validated
public class EnCodeLoginController extends JeecgController<SysUser, ISysUserService> {

    @Autowired
    ISysSmsTemplateService sysSmsTemplateService;
    private static final String VAILD_KEY = "create_admin_sms_token_vaild_";
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${fake.sms.code}")
    private String fakeSmsCode;

    @Value("${fake.sms.phone}")
    private String fakeSmsPhone;
    @Value("${jeecg.sms.secret}")
    private String secret;
    @Autowired
    protected ISysBaseAPI sysBaseApi;
    @Value("${spring.profiles.active}")
    private String profiles;

    /**
     * 获取手机验证码
     *
     * @param
     * @return
     */
    @PostMapping("/getMobileCode")
    @AutoLog(logType = 2, ty = "visit", value = "获取手机验证码")
    public Result<?> getCode(@RequestBody MobileEnParams params, HttpServletRequest request) {
        String token = params.getToken(), mobile = params.getMobile(), sign = params.getSign(), fakeSmsCode = "-1", devProfiles = "dev";
        if (StringUtils.isNotBlank(this.fakeSmsCode) && !fakeSmsCode.equals(this.fakeSmsCode) && StringUtils.isNotBlank(this.fakeSmsPhone) && this.fakeSmsPhone.contains(mobile)) {
            log.warn("{}造假验证码为：{}", mobile, this.fakeSmsCode);
            redisTemplate.opsForValue().set("SEND_VERIFY_CODE_ENT_:" + mobile, fakeSmsCode, 5, TimeUnit.MINUTES);
            return Result.ok();
        }
        if (StrUtil.equals(profiles, devProfiles)) {
            redisTemplate.opsForValue().set("SEND_VERIFY_CODE_ENT_:" + mobile, "000000", 5, TimeUnit.MINUTES);
            return Result.ok("000000");
        }
        String comId = "", dayPhone = "", dayIp = "", hourPhone = "", hourPhoneFive = "5";
        List<DictModel> dictModels = sysBaseApi.queryDictItemsByCode("SMSCODE_USER_KEY_CODE");
        for (DictModel model : dictModels) {
            if ("SMSCODE_USER_CODE".equals(model.getText())) {
                comId = model.getValue();
            }
            if ("SMSCODE_USER_DAY_CODE".equals(model.getText())) {
                dayPhone = model.getValue();
            }
            if ("SMSCODE_IP_DAY_CODE".equals(model.getText())) {
                dayIp = model.getValue();
            }
            if ("SMSCODE_USER_HOUR_CODE".equals(model.getText())) {
                hourPhone = model.getValue();
            }
        }
        String s = DigestUtils.md5Hex(token + mobile + secret);
        Assert.isFalse(!s.equals(sign), "短信token已过期，请重新生成");
        String addr = IPUtils.getIpAddr(request);
        String key = CommonConstant.SMSCODE_USER_CODE + mobile;
        String ipKey = CommonConstant.SMSCODE_IP_DAY_CODE + addr + DateUtil.format(new Date(), "yyyy-MM-dd");
        Boolean hasKey = redisTemplate.hasKey(key);
        Assert.isFalse(hasKey, "短信验证码操作过于频繁");
        String keyHour = CommonConstant.SMSCODE_USER_HOUR_CODE + mobile + DateUtil.format(new Date(), "yyyy-MM-dd");
        Integer countHour = (Integer) redisTemplate.opsForValue().get(keyHour);
        log.info("===一小时验证码的次数====" + countHour);
        if (StringUtils.isEmpty(hourPhone)) {
            hourPhone = hourPhoneFive;
        }
        Assert.isFalse(countHour != null && countHour > Long.valueOf(hourPhone), "1小时内短信验证码操作过于频繁");
        //每天获取验证码次数
        String keyDay = CommonConstant.SMSCODE_USER_DAY_CODE + mobile + DateUtil.format(new Date(), "yyyy-MM-dd");
        Integer stock = (Integer) redisTemplate.opsForValue().get(keyDay);
        if (StrUtil.isNotBlank(dayPhone)) {
            Assert.isFalse(stock != null && stock > Integer.valueOf(dayPhone), "短信验证码操作过于频繁");
        }
        Integer ipStock = (Integer) redisTemplate.opsForValue().get(ipKey);
        if (StrUtil.isNotBlank(dayIp)) {
            Assert.isFalse(ipStock != null && ipStock > Integer.valueOf(dayIp), "今天短信验证码操作过于频繁");
        }
        String redisKey = VAILD_KEY + mobile;
        //已过期
        if (!redisTemplate.hasKey(redisKey)) {
            Result.error("短信发送权限token已过期，请重新生成");
        } else {
            String orignToken = (String) redisTemplate.opsForValue().get(redisKey);
            if (!token.equals(orignToken)) {
                Result.error("短信发送权限token已过期，请重新生成");
            }
        }
        String[] mobile1 = new String[]{mobile};
        boolean b = sysSmsTemplateService.sendSms("ent", mobile1);
        if (b) {
            //当天时间
            Date date = new Date();
            //当天零点
            date = DateUtils.truncate(date, Calendar.DAY_OF_MONTH);
            //第二天零点
            date = DateUtils.addDays(date, +1);
            //一小时过期
            redisTemplate.opsForValue().increment(keyHour, 1);
            redisTemplate.expire(keyHour, 1, TimeUnit.HOURS);
            redisTemplate.opsForValue().increment(keyDay, 1);
            redisTemplate.opsForValue().increment(ipKey, 1);
            redisTemplate.expireAt(keyDay, date);
            redisTemplate.expireAt(ipKey, date);
            redisTemplate.opsForValue().set(key, mobile, Long.valueOf(comId), TimeUnit.MINUTES);
            return Result.ok();
        }
        return Result.ok();
    }

    /**
     * 生成发短信令牌
     */
    @RequestMapping(value = "/create_token.thtml", method = RequestMethod.POST)
    @ResponseBody
    public Result createSmsToken(@RequestBody ModelMap requestBody, HttpServletRequest request,
                                 HttpServletResponse response) {
        Map<String, Object> ret = new LinkedHashMap<String, Object>();
        int phoneLength = 11;
        String phone = (String) requestBody.get("mobile");
        if (StringUtils.isBlank(phone)) {
            return Result.error("请输入手机号！");
        } else if (phone.length() != phoneLength) {
            return Result.error("请输入正确的手机号！");
        }
        String token = IdUtil.getSnowflake(0, 0).nextIdStr();

        //限制IP生成令牌  10秒
        String ip = IPUtils.getIpAddr(request);
        String key = "create_sms_token_limit_" + ip;

        if (redisTemplate.hasKey(key)) {
            return Result.error("操作太频繁，稍后再试！");
        }
        String ipKey = "5";
        List<DictModel> dictModels = sysBaseApi.queryDictItemsByCode("SMSCODE_USER_KEY_CODE");
        for (DictModel model : dictModels) {
            if ("CREATE_TOKEN_IP".equals(model.getText())) {
                ipKey = model.getValue();
            }
        }
        //限制加入缓存；
        redisTemplate.opsForValue().set(key, token, Long.valueOf(ipKey), TimeUnit.SECONDS);

        //验证令牌加入缓存
        String redisKey = VAILD_KEY + phone;
        redisTemplate.opsForValue().set(redisKey, token, 5, TimeUnit.MINUTES);

        ret.put("token", token);
        return Result.ok(ret);

    }
}
